﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace GraphicSplit101
{
    /// <summary>
    /// 自对比
    /// </summary>
    public partial class UCSelfCompare : UserControl
    {
        public string IsOK
        {
            get { return isOK; }            
        }
        public SelfCompareEntity InputParameters
        {            
            set 
            {                                                 
                inputParameters = value;
                byte[,] GrayBytes = GetGrayBytes2D(inputParameters.ProductImage);
                byte[,] ExtractBytes = new byte[inputParameters.RectArea.Width, inputParameters.RectArea.Height];
                int intWidthLength = inputParameters.RectArea.Width + inputParameters.RectArea.X;
                int intHeightLength = inputParameters.RectArea.Height + inputParameters.RectArea.Y;
                int m=0;
                int n = 0;
                for (int i = inputParameters.RectArea.X; i < intWidthLength; i++)
                {
                    for (int j = inputParameters.RectArea.Y; j < intHeightLength; j++)
                    {
                        ExtractBytes[m, n] = GrayBytes[i, j];
                        n+=1;
                    }
                    n = 0;
                    m+=1;
                }
                double dblProductVariance =GetVariance(GrayBytes);
                if (inputParameters.SampleVariance >= dblProductVariance * inputParameters.Tolerance)
                {
                    isOK = "OK";
                }
                else
                {
                    isOK = "NG";
                }                
            }
            get { return inputParameters; }
        }
        public UCSelfCompare()
        {
            InitializeComponent();
            
        }
        private SelfCompareEntity inputParameters;
        private string isOK;
        private double GetVariance(byte[,] bytes)
        {
            double variance = 0;
            double pixelCountX = 1;
            double pixelCountY = 1;
            double pixelCount = 1;
            double grayAverage = 0;
            double graySum = 0;
            try
            {
                pixelCountX = bytes.GetLength(0);
                pixelCountY = bytes.GetLength(1);
                pixelCount = (pixelCountX * pixelCountY);
                for (int j = 0; j < pixelCountY; j++)
                {
                    for (int i = 0; i < pixelCountX; i++)
                    {
                        int gray = bytes[i, j]; 
                        graySum += gray;
                    }
                }
                grayAverage = graySum / pixelCount;
                double diffValueSum = 0;
                for (int j = 0; j < pixelCountY; j++)
                {
                    for (int i = 0; i < pixelCountX; i++)
                    {
                        diffValueSum += Math.Pow(bytes[i, j] - grayAverage, 2);
                    }
                }
                variance = diffValueSum / pixelCount;
                variance = (int)Math.Pow(variance, 0.5);                
                return variance;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return Double.MaxValue;
            }
        }
        private static byte[,] GetGrayBytes2D(Bitmap bitmap)
        {
            if (bitmap == null) return null;
            string strPixelFormat = bitmap.PixelFormat.ToString();
            if (strPixelFormat == "Format8bppIndexed")
            {
                return ConvertGrayBytesToDoubleArray(GetGrayBytesFor8bit(bitmap), bitmap.Width, bitmap.Height);
            }
            else 
            {
                return ConvertGrayBytesToDoubleArray(GetGrayBytesFor32bit(bitmap, 2), bitmap.Width, bitmap.Height);
            }
        }
        private static byte[,] ConvertGrayBytesToDoubleArray(byte[] grayBytes, int imageWidth, int imageHeight)
        {
            byte[,] processedGrayBytes = new byte[imageWidth, imageHeight];
            int k = 0;
            for (int j = 0; j < imageHeight; j++)
            {
                for (int i = 0; i < imageWidth; i++)
                {
                    processedGrayBytes[i, j] = grayBytes[k++];
                }
            }
            return processedGrayBytes;
        }
        private static byte[] GetGrayBytesFor8bit(Bitmap bitmap)
        {
            byte[] grayValues = null;
            try
            {
                if (bitmap != null)
                {
                    Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
                    System.Drawing.Imaging.BitmapData bmpData = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmap.PixelFormat);
                    IntPtr ptr = bmpData.Scan0;
                    int bytes = bitmap.Width * bitmap.Height;
                    grayValues = new byte[bytes];
                    System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);
                    bitmap.UnlockBits(bmpData);
                }
                return grayValues;
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("GetGrayBytesFor8bit:{0}", ex.Message));
                return null;
            }
        }
        private static byte[] GetGrayBytesFor32bit(Bitmap bitmap, int intMethod)
        {
            byte[] rgbValues = null;
            byte[] grayValues = null;
            if (bitmap != null)
            {
                double r = 0, g = 0, b = 0;
                switch (intMethod)
                {
                    case 0:
                        {
                            r = 0.299;
                            g = 0.587;
                            b = 0.114;
                            break;
                        }
                    case 1:
                        {
                            r = 1;
                            g = 0;
                            b = 0;
                            break;
                        }
                    case 2:
                        {
                            r = 0;
                            g = 1;
                            b = 0;
                            break;
                        }
                    case 3:
                        {
                            r = 0;
                            g = 0;
                            b = 1;
                            break;
                        }
                    default:
                        r = 0;
                        g = 1;
                        b = 0;
                        break;
                }
                try
                {
                    Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
                    System.Drawing.Imaging.BitmapData bmpData = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmap.PixelFormat);
                    IntPtr ptr = bmpData.Scan0;
                    int bytes = bitmap.Width * bitmap.Height;
                    int rgbBytes = bytes * 3;
                    rgbValues = new byte[rgbBytes];
                    grayValues = new byte[bytes];
                    System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, rgbBytes);
                    int j = 0;
                    for (int i = 0; i < bytes; i += 3)
                    {
                        double colorTemp = rgbValues[i + 2] * r + rgbValues[i + 1] * g + rgbValues[i] * b;
                        grayValues[j++] = (byte)colorTemp;
                    }
                    bitmap.UnlockBits(bmpData);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(string.Format("GetGrayBytesFor32bit:{0}", ex.Message));
                }
            }
            return grayValues;
        }
    }
    public class SelfCompareEntity
    {
        private Bitmap productImage;
        private Rectangle rectArea;
        private float sampleVariance=0;
        private float tolerance=1;

        public Rectangle RectArea
        {
            get { return rectArea; }
            set { rectArea = value; }
        }
        public Bitmap ProductImage
        {
            get { return productImage; }
            set { productImage = value; }
        }
        public float SampleVariance
        {
            get { return sampleVariance; }
            set { sampleVariance = value; }
        }
        public float Tolerance
        {
            get { return tolerance; }
            set { tolerance = value; }
        }

    }
}
